home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiniExamples
/
AppKit
/
WhatsUpDoc
/
DocController.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
8KB
|
337 lines
/* DocController.m
* Purpose: This is the main controlling class for this application.
* DocController loads the Info and Help nib files on demand.
* DocController also handles the multiple documents that can
* be open at any time using the Document class -- including
* keeping a count, tracking the current active document,
* managing the open and save panels, etc.
*
* You may freely copy, distribute, and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied, as to its
* fitness for any particular use.
*
* Written by: R. Dunbar Poor
* Created: 28/April/1991
*
*/
#import "DocController.h"
#import "Document.h"
#import <appkit/Application.h>
#import <appkit/Cell.h>
#import <appkit/OpenPanel.h>
#import <appkit/Panel.h> /* for NX_ALERTxxx */
#import <strings.h>
#import <sys/param.h>
@interface DocController(DocControllerPrivate)
- _countDocuments:aDocument :sender;
- _save:aDocument :sender;
- _collectEditedDocuments:aDocument :editedDocuments;
- _hide:aDocument :sender;
@end
@implementation DocController
- init
{
[super init];
return self;
}
- free
{
return [super free];
}
- showInfo:sender
{
if (!infoPanel) {
[NXApp loadNibSection:"Info.nib" owner:self withNames:NO];
}
[infoPanel makeKeyAndOrderFront:sender];
return self;
}
- showHelp:sender
{
if (!helpPanel) {
[NXApp loadNibSection:"Help.nib" owner:self withNames:NO];
}
[helpPanel makeKeyAndOrderFront:sender];
return self;
}
- activeDocument
{
return activeDocument;
}
- setActiveDocument:aDocument
{
char buf[100];
activeDocument = aDocument;
/* display the message of the current document */
[activeDocumentField setStringValue:[activeDocument message]];
/* count and display the number of documents present */
documentCount = 0;
[self performForDocuments:@selector(_countDocuments::) with:self];
sprintf(buf,"There %s %d active document%s.",
documentCount==1?"is":"are",
documentCount,
documentCount==1?"":"s");
[documentCountField setStringValue:buf];
/* adjust the menu cells accordingly */
if (activeDocument) {
[saveMenu setEnabled:YES];
[saveAsMenu setEnabled:YES];
[saveToMenu setEnabled:YES];
[saveAllMenu setEnabled:YES];
if ([activeDocument isDocEdited]) {
[revertMenu setEnabled:YES];
} else {
[revertMenu setEnabled:NO];
}
[closeMenu setEnabled:YES];
} else {
[saveMenu setEnabled:NO];
[saveAsMenu setEnabled:NO];
[saveToMenu setEnabled:NO];
[saveAllMenu setEnabled:NO];
[revertMenu setEnabled:NO];
[closeMenu setEnabled:NO];
}
return self;
}
- _countDocuments:aDocument :sender
{
documentCount += 1;
return self;
}
- unsetActiveDocument:aDocument
{
if (activeDocument == aDocument) {
activeDocument = nil;
}
/* force an update of the document count */
[self setActiveDocument:activeDocument];
return self;
}
- open:sender
/*
* Open one or more existing documents
*/
{
const char *const *files;
static const char *const fileType[2] = {DOCUMENT_TYPE, NULL};
id openPanel;
char fullName[MAXPATHLEN];
openPanel = [[OpenPanel new] allowMultipleFiles:YES];
/* run the open panel, filtering for out type of document */
if ([openPanel runModalForTypes:fileType]) {
/* open all the files returned by the open panel */
files = [openPanel filenames];
for (files = [openPanel filenames]; files && *files; files++) {\
sprintf(fullName,"%s/%s",[openPanel directory],*files);
if (![[Document alloc] initFromFile:fullName]) {
NXRunAlertPanel("Open","Can't open %s", "Okay", NULL, NULL, *files);
}
}
}
return self;
}
- new:sender
/*
* Open a new, empty document
*/
{
[[Document alloc] init];
return self;
}
- save:sender
{
return [activeDocument save:sender];
}
- saveAs:sender
{
return [activeDocument saveAs:sender];
}
- saveTo:sender
{
return [activeDocument saveTo:sender];
}
- saveAll:sender
{
return [self performForDocuments:@selector(_save::) with:sender];
}
- _save:aDocument :sender
{
return [aDocument save:sender];
}
- revert:sender
{
return [activeDocument revert:sender];
}
- close:sender
{
return [activeDocument close:sender];
}
- performForDocuments:(SEL)aSelector with:anObject
/*
* Send [self aSelector :aDocument :anObject] for each Document in the
* application. We depend on the fact that each Document has an associated
* window and that each Document is the delegate of its window.
*/
{
id window, windows = [NXApp windowList];
int i=0;
while (window = [windows objectAt:i++]) {
id document = [window delegate];
if (document && ([document class] == [Document class])) {
[self perform:aSelector with:document with:anObject];
}
}
return self;
}
- (int)app:sender openFile:(const char *)path type:(const char *)type
/*
* This method is performed whenever a user opens a document from the Workspace
* Manager. (This method has replaced the obsolete method appOpenFile:type:)
*/
{
if (type && !strcmp(type, DOCUMENT_TYPE)) {
if (![[Document alloc] initFromFile:path]) {
NXRunAlertPanel("Open","Can't open %s","Okay",NULL,NULL,path);
return NO;
} else {
return YES;
}
}
return NO;
}
- (BOOL)appAcceptsAnotherFile:sender
/*
* Inform the workspace that we can open multiple files.
*/
{
return YES;
}
- appDidInit:sender
/*
* When the app is launched, create an empty document if we haven't opened
* a document already.
*/
{
if (!activeDocument) {
[self new:self];
}
return self;
}
- appWillTerminate:sender
{
int i, editedCount, choice;
List *editedDocuments = [[List alloc] init];
do {
/*
* Make a list of edited documents and count how many there are.
*/
[editedDocuments empty];
[self performForDocuments:@selector(_collectEditedDocuments::)
with:editedDocuments];
editedCount = [editedDocuments count];
if (editedCount > 0) {
/*
* If there is one or more unsaved document, ask the user if they want
* to review documents, quit, or abort the quit.
*/
choice = NXRunAlertPanel(
"Quit",
"There are unsaved documents.\nReview them?",
"Review", /* NX_ALERTDEFAULT */
"Quit Anyway", /* NX_ALERTALTERNATE */
"Cancel"); /* NX_ALERTOTHER */
switch (choice) {
case NX_ALERTDEFAULT:
/* Give the user the chance to review the edited document(s). */
for (i=0;i<editedCount;i++) {
[[editedDocuments objectAt:i] close:self];
}
break;
case NX_ALERTALTERNATE:
/* user selected Quit Anyway, just go to endgame */
editedCount = 0;
break;
case NX_ALERTOTHER:
/* user selected Cancel, return nil to cancel the quit */
[editedDocuments free];
return nil;
break;
}
}
} while (editedCount > 0);
/*
* ENDGAME:
* hide all the windows first to avoid the irritation of watching
* each window become the main window in turn while we're closing
* documents. After all, we simply want to quit...
*/
[self performForDocuments:@selector(_hide::) with:self];
[editedDocuments free];
/* ...and terminate without any futher ado (or review of docs) */
return self;
}
- _collectEditedDocuments:aDocument :editedDocuments
/*
* Collect those documents that have been modified into the editedDocuments
* list. Called from performForDocuments:with:.
*/
{
if ([aDocument isDocEdited]) {
[editedDocuments addObject:aDocument];
}
return self;
}
- _hide:aDocument :sender
/*
* hide one document.
*/
{
return [aDocument hideDocument:sender];
}
@end